package com.briup.sms.storage;

import com.briup.day13.AssertUtil;
import com.briup.sms.model.User;
import lombok.Getter;

import java.util.Arrays;
import java.util.StringJoiner;

/**
 * 用户数据存储器，负责存储和管理用户数据
 */
public class UserStorage {
    /**
     * 用于实际存储和管理用户数据的数组
     */
    private User[] values;
    /**
     * 用于统计数组中实际用户的个数
     */
    @Getter
    private int size = 0;

    public UserStorage() {
        // 如果使用的是无参构造器，那么默认长度为10
        this(10);
    }

    public UserStorage(int capacity) {
        // 根据用户传入的容量，给数组进行初始化
        values = new User[capacity];
    }

    // 对数据的存储和管理，无非就是增删改查
    public void add(User user) {
        // 在添加元素之前，对数组的长度范围进行校验
        checkCapacity(size + 1);
        values[size++] = user;
    }

    /**
     * 批量添加用户数据
     *
     * @param users 用户数据数组对象
     */
    public void add(User[] users) {
        checkCapacity(size + users.length);
        // 直接将你传入的用户数组数据写入到数组原有数据后面即可
        // 从values数组中的size下标开始写起，写入users.length个元素
        System.arraycopy(users, 0, values, size, users.length);
        // 修改size，调整数组中元素的实际个数
        size += users.length;
    }

    /**
     * 根据指定的下标进行删除
     *
     * @param index 下标
     * @return 被删除的元素对象
     */
    public User delete(int index) {
        // 先校验该下标是否可用
        checkRange(index);
        // 根据下标找到该下标位置的元素
        User user = values[index];
        // 删除元素，即将该下标位置后的元素覆盖掉该元素即可
        System.arraycopy(values, index + 1, values, index,
                size - index - 1);
        // 最后一个元素位置需要置空
        values[--size] = null;
        return user;
    }

    /**
     * 根据用户名删除用户
     *
     * @param username 用户名
     * @return 被删除的用户对象
     */
    public User delete(String username) {
        AssertUtil.hasText(username);
        // 先根据用户名找到对应用户的下标
        for (int i = 0; i < size; i++) {
            if (username.equals(values[i].getUsername())) {
                // 删除找到的第一个符合条件的用户
                return delete(i);
            }
        }
        // 如果没有符合你传入的用户名的用户，那么直接返回null
        return null;
    }

    private void checkRange(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException(
                    String.format("下标越界：长度为%s，您传入的为%s", size, index)
            );
        }
    }

    /**
     * 根据传入的参数与当前数组长度进行比较，
     * 查看添加当前元素是否会越界
     *
     * @param i 元素个数
     */
    private void checkCapacity(int i) {
        // 如果当前i小于等于数组长度，那么直接继续添加元素即可
        if (i <= values.length) {
            return;
        } else {
            // 如果i大于数组长度，那么说明当前数组无法支持新数据的存储，
            // 所以应该对当前数组进行扩容
            grow(i);
        }
    }

    /**
     * 对数组进行扩容的方法
     *
     * @param size 添加元素至少所需的数组大小
     */
    private void grow(int size) {
        // 获取原始的数组容量
        int oldCapacity = values.length;
        // 计算新数组的容量，建议新数组的容量是原本数组容量的2倍
        // 如果添加元素所需的数组大小至少是2倍以上，
        // 那么就使用size作为数组的容量
        int newCapacity = Math.max(oldCapacity << 1, size);
        // 创建新数组对象，并且将原有数组的数据写如到新数组中
        values = Arrays.copyOf(values, newCapacity);
    }

    public String toString() {
        StringJoiner sj = new StringJoiner(",", "Users[", "]");
        for (int i = 0; i < size; i++) {
            sj.add(values[i].toString());
        }
        return sj.toString();
    }
}